package app.species.ANN;

import java.io.Serializable;

//contains a soma and axon(s)
//this is the class you want when creating the networks individual nodes for a brain
//a neuron contains a single soma and can contain multiple incoming /outgoing axons
//this class is responsible for changing values within the soma based on incoming connections
//will change change outgoing link values of axons as well
//i decided to implement features for input/output/bias and hidden neurons rather then
//extend them into their own class because it makes it easier when activating the whole network
public abstract class Neuron implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 7407970385068125653L;
	protected Axon[] incomingAxons; // array of pointers to incoming links
	protected Axon[] outgoingAxons; // same for outgoing links
	protected Soma soma; // the current node
	private boolean alreadySetAxons;

	// neuron needs to know its id information and number of axons and its soma;
	// constructor for all neurons
	public Neuron(Soma s, Axon[] in, Axon[] out) {

		this.soma = s;
		this.incomingAxons = in;
		this.outgoingAxons = out;
		this.alreadySetAxons = false;

	}

	// reads output value of all incoming axons and sums in node
	// sends nodes summed input to activation function and sets outputs value to
	// all outgoing axons input
	// then pushes the value thru the axon, multiplying weight
	// this is a single timestep
	// dont use this unless neurons are firing in order from input to output
	public void fire() {

		double sum = 0.0;
		boolean oneInputActive = false; // at least one input active

		for (int i = 0; i < this.incomingAxons.length; i++) {

			if (this.incomingAxons[i].isActive()) {
				sum += this.incomingAxons[i].output;
				oneInputActive = true;
			}

		}

		if (oneInputActive) {

			this.soma.setActive(true);
			this.soma.input = sum;
			this.soma.activate();

			for (int i = 0; i < this.outgoingAxons.length; i++) {
				this.outgoingAxons[i].input = this.soma.output;
			}

		}

	}
	
	public Soma getSoma(){
		return soma;
	}

	public void setOutAxonsActive() {

		if (!this.alreadySetAxons) {

			for (int i = 0; i < this.outgoingAxons.length; i++) {
				this.outgoingAxons[i].setActive(true);
			}

			this.alreadySetAxons = true;

		}
	}

}
